package p2p;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.DatagramPacket;
import javax.swing.Timer;

/**
 * @author Bruno
 */
public class P2PFileThread extends Thread implements ActionListener {

	/** Number of miliseconds per file in the "Files" list the thread waits after sending a chunk to the network. */
	static private final int msSleepAfterSendPerFile = 1;
	/** Timeout, in miliseconds, before sending another GET message to the network after receiving a chunk. */
	static private final int msTimeOut = 1500;

	private Timer timeout = new Timer(msTimeOut, this);

	// Called when timeout occurs
	public void actionPerformed(ActionEvent e) {
		if(file.isComplete())
			return;
		
		file.askForRemainingChunks(); // Ask the network for the remaining chunks

		timeout.setDelay(msTimeOut);
		timeout.start();
	}

	@Override
	public void run() {
		
		while(true) {
			// Check if any chunk is waiting to be writen to the disc
			while(file.hasReceivedChunks()) {
				if(stopRequested) {
					timeout.stop();
					return;
				}

				NetworkChunk netChunk = file.popReceivedChunk();
				int chunkNumber = netChunk.getChunkNumber();
				
				if(!file.isChunkAvailable(chunkNumber)) {
					timeout.stop();
					byte[] data = netChunk.getData();
					file.writeChunk(chunkNumber, data);
					if(!file.isComplete()) {
						timeout.setDelay(msTimeOut);
						timeout.start();
					}
				}
			}

			if(stopRequested) {
				timeout.stop();
				return;
			}

			// Respond to a random requested chunk
			int index = file.getRandomRequestedChunkIndex();
			if(index >= 0) {
				// Send the chunk to the data port
				NetworkChunk netChunk = new NetworkChunk(file.getHash(), index, file.getChunk(index));

				DatagramPacket packet = new DatagramPacket(netChunk.getBuffer(), netChunk.getBuffer().length, Global.multicastInetAddr, Global.dataPort);
				try {
					Global.dataSocket.send(packet);
					file.removeRequestedChunk(index);

					// Sleep for a bit (ammount of time depends on the number of files in the list)
					Thread.sleep(msSleepAfterSendPerFile * P2PFileList.getNumActiveFiles());
				} catch (Exception ex) {
				}
			}

			// If there is nothing to do, sleep
			if(!file.hasReceivedChunks() && !file.hasRequestedChunks()) {
				try {
					Thread.sleep(500);
				} catch (InterruptedException ex) {	}
			}
		}
	}

	public synchronized void start(P2PFile file) {
		this.file = file;
		if(!file.isComplete()) {
			timeout.setDelay(msTimeOut);
			timeout.start();
		}
		stopRequested = false;
		start();
	}


	public void requestStop() {
		stopRequested = true;
		try {
			join();
		} catch (InterruptedException ex) {
		}
	}


	private P2PFile file;
	private boolean stopRequested = false;
}
